//
//  YSRequest.m
//  Pods
//
//  Created by zhanglu on 16/3/3.
//
//

#import "YSRequest.h"
#import "YSRequestManager.h"
#import "YSUserManager.h"
@interface YSRequest ()

@property (nonatomic, strong) UIImage *image;
@property (nonatomic, strong) NSData *imageData;
@property (nonatomic, assign) CGFloat imageCompressionQuality;
@property (nonatomic, copy) NSString *imageName;
@property (nonatomic, copy) NSString *imageType;

@end

@implementation YSRequest

- (nonnull instancetype)init
{
    if (self = [super init]) {
        self.timeoutInterval = 15;
        self.requestMethod = YSRequestMethodGet;
        self.requestSerializerType = YSRequestSerializerTypeHTTP;
        self.responseSerializerType = YSResponseSerializerTypeJSON;
    }
    return self;
}

- (NSString *)imageName
{

    return _imageName? : [YSRequestConfig shared].defaultUploadImageName;
}

- (NSString *)imageType
{
    return _imageType? : [YSRequestConfig shared].defaultUploadImageType;
}

- (CGFloat)imageCompressionQuality
{
    return _imageCompressionQuality > 0 && _imageCompressionQuality < 1 ? _imageCompressionQuality : [YSRequestConfig shared].defaultUploadImageCompressionQuality;
}

#pragma mark - response 相关信息
- (NSNumber *)responseStatusCode {
    return self.response == nil ? nil : @(self.response.statusCode);
}

- (NSDictionary *)responseHeaders {
    return self.response.allHeaderFields;
}

- (YSRequestMethod)getRequestMethodUsingString: (nonnull NSString *)methodString
{
    YSRequestMethod method = 0;
    if ([methodString isEqualToString:@"GET"]) {
        method = YSRequestMethodGet;
    } else if ([methodString isEqualToString:@"POST"]) {
        method = YSRequestMethodPost;
    } else if ([methodString isEqualToString:@"HEAD"]) {
        method = YSRequestMethodHead;
    } else if ([methodString isEqualToString:@"PUT"]) {
        method = YSRequestMethodPut;
    } else if ([methodString isEqualToString:@"DELETE"]) {
        method = YSRequestMethodDelete;
    }
    return method;
}

+ (nonnull instancetype)requestWithURL: (nonnull NSString *)urlString AndMethod: (nonnull NSString *)methodString
{
    YSRequest *request = [[YSRequest alloc] init];
    request.requestUrl = urlString;
    request.requestMethod = [request getRequestMethodUsingString:methodString];
    return request;
}

+ (nonnull instancetype)requestWithCategory: (nonnull NSString *)category AndName: (nonnull NSString *)name
{
    YSRequest *request = [[YSRequest alloc] init];
    
    NSDictionary *serviceConfig = [[YSRequestConfig shared] config];
    NSDictionary *urlItem = (NSDictionary *)serviceConfig[@"service"][category][name];
    
    request.requestUrl = [[YSRequestConfig shared] urlStringFromName:[NSString stringWithFormat:@"%@.%@",category, name]];
    
    NSString *methodString = urlItem[@"method"];
    request.requestMethod = [request getRequestMethodUsingString:methodString];
    
    return request;
}

+ (nonnull instancetype)requestWithName: (nonnull NSString *)pathName
{
    NSArray *nameArray = [pathName componentsSeparatedByString:@"."];
    NSString *category = nameArray[0];
    NSString *name = nameArray[1];
    
    // todo: deal with error
    
    return [YSRequest requestWithCategory:category AndName:name];
}

- (nonnull NSDictionary *)resultDictionaryWithDict:(nonnull NSDictionary *)params
{//    if (textCheckingResultArray.count > 0)
    
    //  match  /:(\w+)
    NSError *error = nil;
    // replace parameters in url
    NSString *url = self.requestUrl;
    NSRegularExpression* regex = [NSRegularExpression regularExpressionWithPattern:@"/:(\\w+)" options:0 error:&error];
    NSArray* textCheckingResultArray = [regex matchesInString:url options:0 range:NSMakeRange(0, url.length)];
    
    NSMutableDictionary* mutableParams = [NSMutableDictionary dictionaryWithDictionary:params];
    for (NSTextCheckingResult* match in textCheckingResultArray) {
        NSRange paramNameRange = NSMakeRange(match.range.location + 2, match.range.length - 2);
        NSString* paramName = [self.requestUrl substringWithRange:paramNameRange];
        if (paramName != nil) {
            // find a URL param, try to match form params
            BOOL foundParam = NO;
            for (NSString* key in [mutableParams allKeys]) {
                if ([key isEqualToString:paramName]) {
                    foundParam = YES;
                    url = [url stringByReplacingOccurrencesOfString:[NSString stringWithFormat:@":%@", paramName]
                                                         withString:[NSString stringWithFormat:@"%@", params[key]]];
                    [mutableParams removeObjectForKey:paramName];
                }
            }
            if (!foundParam) {
                // todo: not enough params
                abort();
            }
        }
    }
    [self setRequestUrl:url];
    return [NSDictionary dictionaryWithDictionary:mutableParams];
}

+ (nonnull NSURL *) urlWithName:(nonnull NSString *) pathName
{
    return [NSURL URLWithString:[[YSRequestConfig shared] urlStringFromName:pathName]];
}

+ (nonnull instancetype)requestWithURLString: (nonnull NSString *)urlString AndRequestMethod: (YSRequestMethod)requestMethod
{
    YSRequest *request = [[YSRequest alloc] init];
    [request setRequestUrl: urlString];
    [request setRequestMethod: requestMethod];
    return request;
}

+ (nonnull instancetype)requestWithNSURL: (nonnull NSURL *)url AndRequestMethod: (YSRequestMethod)requestMethod
{
    return [self requestWithURLString:[url absoluteString] AndRequestMethod:requestMethod];
}

#pragma mark - 上传图片
+ (instancetype)requestWithName:(NSString *)name image:(UIImage *)image
{
    
    return [YSRequest requestWithName:name image:image compressionQuality:1 imageName:[YSRequestConfig shared].defaultUploadImageName imageType:[YSRequestConfig shared].defaultUploadImageType];
}

+ (instancetype)requestWithName:(NSString *)name image:(UIImage *)image compressionQuality:(CGFloat)compressionQuality imageName:(NSString *)imageName imageType:(NSString *)imageType
{
    YSRequest *request = [YSRequest requestWithName:name];
    request.image = image;
    request.imageData = UIImageJPEGRepresentation(image, compressionQuality > 0 && compressionQuality <= 1?:[YSRequestConfig shared].defaultUploadImageCompressionQuality);
    request.imageName = imageName;
    request.imageType = imageType;
    return request;
}

+ (instancetype)requestWithName:(NSString *)name imageData:(NSData *)imageData
{
    return [YSRequest requestWithName:name imageData:imageData imageName:[YSRequestConfig shared].defaultUploadImageName imageType:[YSRequestConfig shared].defaultUploadImageType];
}

+ (instancetype)requestWithName:(NSString *)name imageData:(NSData *)imageData imageName:(NSString *)imageName imageType:(NSString *)imageType
{
    YSRequest *request = [YSRequest requestWithName:name];
    request.imageData = imageData;
    request.imageName = imageName;
    request.imageType = imageType;
    return request;
}

- (void)sendWithParameters:(nonnull NSDictionary *) params
                   success:(nullable void(^)(id _Nonnull response)) success
                   failure:(nullable void(^)(YSRequest * _Nonnull request)) failure
{
    [self sendWithParameters:params delegate:nil success:success failure:failure];
}
- (void)sendWithParameters:(nonnull NSDictionary *) params
                  delegate:(id)delegate
                   success:(nullable void(^)(id _Nonnull response)) success
                   failure:(nullable void(^)(YSRequest * _Nonnull request)) failure
{
    if (delegate && [delegate isKindOfClass:[NSObject class]]) {
        @weakify(self);
        [((NSObject *)delegate).rac_willDeallocSignal subscribeNext:^(id x) {
            @strongify(self);
            [self.sessionDataTask cancel];
        }];
        if ([delegate isKindOfClass:[UIViewController class]]) {
            [[((UIViewController *)delegate) rac_signalForSelector:@selector(viewWillDisappear:)] subscribeNext:^(id x) {
                @strongify(self);
                [self.sessionDataTask cancel];
            }];
        }
    }
    // 过滤非法URL
    if (self.requestUrl.length == 0) {
        return;
    }
    YSRequestConfig * config = [YSRequestConfig shared];
    
    // 添加额外参数，如遇到Key相同，YSRequest设置的参数会覆盖额外参数。
    NSMutableDictionary *dict = [NSMutableDictionary dictionaryWithDictionary:config.hookExtraParamBlock()];
    [dict addEntriesFromDictionary:params];
    NSDictionary *dictParam = [self resultDictionaryWithDict:[dict copy]];
    
    self.requestParam = dictParam;
    
    if (config.hookRequestBlock) {
        //在这个时刻可以去取[YSRequestManager manager]
        config.hookRequestBlock(self);
    }
    
    [[YSRequestManager manager] sendWithRequest:self success:^(id  _Nonnull response) {
        
        if (success) {
            success(response);
        }
     
        [[YSUserManager sharedManager] checkTokenByResponse:response];
       
    } failure:^(YSRequest * _Nonnull request) {
        if (failure) {
            failure(request);
        }
    }];
}

+ (NSString *) requestMethodString:(YSRequestMethod) method
{
    switch (method) {
        case YSRequestMethodGet:
            return @"GET";
        case YSRequestMethodPost:
            return @"POST";
        case YSRequestMethodPut:
            return @"PUT";
        case YSRequestMethodPatch:
            return @"PATCH";
        case YSRequestMethodDelete:
            return @"DELETE";
        case YSRequestMethodHead:
            return @"HEAD";
    }
}

- (void)dealloc
{
    [self.sessionDataTask cancel];
}

- (void)cancle
{
    [self.sessionDataTask cancel];
}

@end

